import * as $util from '/lib/hc-util.js'

export default function(cfg) {
    //use the document object as container， can drag mouse on whole screen，especially mouseup event
    let container = document; 
    var selectbox = document.getElementById('selectbox');

    var ongoing = false;
    var posx
    var posy
    var selectedList = []
    var layoutUpdated = function(list) {
        console.warn('layout is changed, need to refresh the relative docouments')
    };

    var containerClicked = function() {
        console.warn('the container is clicked, need to lose other focus and its relatives ');
    }

    if (cfg) {
        if (cfg.layoutUpdated) layoutUpdated = cfg.layoutUpdated;
        if (cfg.containerClicked) containerClicked = cfg.containerClicked;
    }

    function $pos(node, posName) //posName:left|top|width|height which end with 'px'
    {
        let pos = node.style[posName];
        return parseInt(pos.substr(0, pos.length - 2));
    }

    function $left(node) {
        return $pos(node, 'left')
    }

    function $top(node) {
        return $pos(node, 'top')
    }

    function selectNode(node) {
        $util.addClass(node, 'flownode-selected');
        selectedList.push(node)
    }
    

    function handleMousedown(evt) {
        // console.log('mousedown from ' + evt.srcElement.id, evt)

        //start a drag from container，avoid restore selected state while to execute a command
        if (evt.srcElement.id != 'diagramContainer') return;

        clearSelectedList(); //reset and restart to select

        containerClicked();

        //starting...
        ongoing = true;
        posx = evt.pageX ;
        posy = evt.pageY;

        selectbox.style.left = posx + "px";
        selectbox.style.top = posy + "px";
        selectbox.style.width = '0px';
        selectbox.style.height = '0px';
        selectbox.style.display = 'block';
    }

    function clearSelectedList() {
        selectedList.forEach(it => {
            $util.removeClass(it, 'flownode-selected')
        });
        selectedList.splice(0, selectedList.length); ;
    }

    function handleMousemove(evt) {
        if (!ongoing) return;

        selectbox.style.left = Math.min(evt.pageX, posx) + "px";
        selectbox.style.top = Math.min(evt.pageY, posy) + "px";
        selectbox.style.width = Math.abs(evt.pageX - posx) + "px";
        selectbox.style.height = Math.abs(evt.pageY - posy) + "px";

        evt.preventDefault(); //prevent to select the text in container
    }

    function assureEndState() {
        if (ongoing) {
            ongoing = false;
            selectbox.style.display = 'none';
            return true;
        }
        return false;
    }

    function handleMouseup(evt) {
        // console.log('mouseup from ' + evt.srcElement.id, evt)

        if (assureEndState()) {
            let left = $left(selectbox); 
            let top = $top(selectbox); 
            let width = $pos(selectbox, 'width'); 
            let height = $pos(selectbox, 'height'); 

            selectNodeInBox({
                left: left,
                top: top,
                right: left + width,
                bottom: top + height,
            });
        }
    }

    function handleKeyDown(evt) {
        // console.log('handleKeyDown', evt)

        if (!evt.ctrlKey || selectedList.length == 0) return;

        let code = evt.code;
        switch (code) {
            case 'ArrowLeft':
                moveSelectedList('left', -10);
                evt.preventDefault();
                break;
            case 'ArrowRight':
                moveSelectedList('left', 10);
                evt.preventDefault();
                break;
            case 'ArrowUp':
                moveSelectedList('top', -10);
                evt.preventDefault();
                break;
            case 'ArrowDown':
                moveSelectedList('top', 10);
                evt.preventDefault();
                break;
            default:
                return;
        }
    }

    function moveSelectedList(posName, delta) //left | top , ±10
    {
        if (selectedList.length == 0) return;

        selectedList.forEach(it => {
            let oldPos = it.style[posName]
            let newPos = parseInt(oldPos.substr(0, oldPos.length - 2)) + delta;
            it.style[posName] = newPos + 'px';
        });

        layoutUpdated(selectedList)
    }

    function centerSelectedList(posName, sizeName) //eg, left | top, offsetWidth | offsetHeight
    {
        if (selectedList.length <= 1) return;

        let possum = 0;
        let sizesum = 0;
        selectedList.forEach(it => {
            let pos = it.style[posName];
            possum += parseInt(pos.substr(0, pos.length - 2));
            sizesum += it[sizeName];
        })

        let posavg = possum / selectedList.length;
        let sizeavg = sizesum / selectedList.length;

        selectedList.forEach(it => {
            let newpos = posavg + (sizeavg - it[sizeName]) / 2
            it.style[posName] = newpos + 'px';
        })

        layoutUpdated(selectedList)
    }
    
    function selectNodeInBox(box) {
        let list = document.querySelectorAll('.flownode');

        list.forEach(it => {
            let left = $left(it);
            let top = $top(it);
            let width = it.offsetWidth;
            let height = it.offsetHeight;

            if (left > box.left && top > box.top &&
                left + width < box.right && top + height < box.bottom) {
                    
                selectNode(it)
            }
        })
    }

    var locatedNode = null;
    var locatedOffsetX = 0;
    var locatedOffsetY = 0;
    function handleNodeMousedown(evt) {
        // console.log('handleNodeMousedown', evt.srcElement.id, evt)
        if (!(/^nid\d{1,}$/.test(evt.srcElement.id))) return;

        // locatedOffsetX = evt.offsetX ;
        // locatedOffsetY = evt.offsetY ;
        locatedOffsetX = evt.pageX - $left(evt.srcElement);
        locatedOffsetY = evt.pageY - $top(evt.srcElement) ;
        
        locatedNode = evt.srcElement;

        if (selectedList.findIndex(it => it == locatedNode) < 0) {

            clearSelectedList()

            selectNode(locatedNode)
        }
    }

    function handleNodeMousemove(evt) {
        // console.log('handleNodeMousemove', evt.srcElement.id)

        if (locatedNode == null) return;

        let newLeft = (evt.pageX - locatedOffsetX ) ;
        let newTop = (evt.pageY - locatedOffsetY ) ;
        
        let oldLeft = $left(locatedNode);
        let oldTop = $top(locatedNode);

        selectedList.forEach(it => {
            it.style.left = $left(it) + newLeft - oldLeft + 'px';
            it.style.top = $top(it) + newTop - oldTop + 'px';
        })

        layoutUpdated(selectedList);
    }

    function handleNodeMouseup(evt) {
        // console.log('handleNodeMouseup', evt.srcElement.id, evt)

        locatedNode = null;
    }

    //event listener to select the flow node
    container.addEventListener('mousedown', handleMousedown, false);
    container.addEventListener('mousemove', handleMousemove, false);
    container.addEventListener('mouseup', handleMouseup, false);
    selectbox.addEventListener('mouseup', handleMouseup, false);

    //event listener to handle key-board movement
    container.addEventListener('keydown', handleKeyDown, false);

    //event handler to move the selected flow node
    container.addEventListener('mousedown', handleNodeMousedown, false);
    container.addEventListener('mousemove', handleNodeMousemove, false);
    container.addEventListener('mouseup', handleNodeMouseup, false);

    return {
        moveSelected: moveSelectedList, //left | top , +10 | -10
        centerSelected: centerSelectedList, // left | top, offsetWidth | offsetHeight
        selectedList: selectedList,
        control:control,
    }
}

var control = {
    props: {
        layouttool: {
            type: Object,
            default: {}
        }
    },
    methods: {
        handleLayoutButtonClick: function() {
            this.$message({
                type: 'info',
                message: '请鼠标框选（左键按下拖动）流程节点后，再进行布局操作。'
            })
        },
        handleLayout: function(val) {
            switch (val) {
                case 'centerhorizontal':
                    this.layouttool.centerSelected('left', 'offsetWidth');
                    break;
                case 'centervertical':
                    this.layouttool.centerSelected('top', 'offsetHeight');
                    break;
                case 'moveup':
                    this.layouttool.moveSelected('top', -10);
                    break;
                case 'movedown':
                    this.layouttool.moveSelected('top', +10);
                    break;
                case 'moveleft':
                    this.layouttool.moveSelected('left', -10);
                    break;
                case 'moveright':
                    this.layouttool.moveSelected('left', +10);
                    break;
                default:
                    console.warn('handleLayout:function(val):' + val);
                    break;
            }
        },
    },
    template: `
        <el-dropdown size='medium' split-button type="primary" :hide-on-click="false" @command="handleLayout"
                @click="handleLayoutButtonClick">
                流程布局
                <el-dropdown-menu slot="dropdown" style="opacity: 0.8;">
                    <el-dropdown-item command='centerhorizontal' :disabled='layouttool.selectedList.length<=1'>水平居中</el-dropdown-item>
                    <el-dropdown-item command='centervertical' :disabled='layouttool.selectedList.length<=1'>垂直居中</el-dropdown-item>
                    <el-dropdown-item divided command='movedown' :disabled='layouttool.selectedList.length<=0'>向下移动(Ctrl
                        + ↓ )</el-dropdown-item>
                    <el-dropdown-item command='moveup' :disabled='layouttool.selectedList.length<=0'>向上移动(Ctrl
                        + ↑ )</el-dropdown-item>
                    <el-dropdown-item command='moveleft' :disabled='layouttool.selectedList.length<=0'>向左移动(Ctrl
                        + ←)</el-dropdown-item>
                    <el-dropdown-item command='moveright' :disabled='layouttool.selectedList.length<=0'>向右移动(Ctrl
                        + →)</el-dropdown-item>
                </el-dropdown-menu>
       </el-dropdown>
        `
};